package com.ifonly.activerecord;

import com.ifonly.activerecord.exceptions.SqlExecuteException;
import com.ifonly.activerecord.helpers.ColumnTypeHelper;
import com.ifonly.config.Configuration;
import com.ifonly.reports.Reporter;

import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * TableBuilder 建立数据库表 与 模型的映射关系
 *
 * @author <a href="mailto:ifonlymaster@163.com">ifonly</a>
 * @version 1.0 2015-12-18 15:31
 * @since JDK 1.6
 */
class TableBuilder {
    Configuration instance = Configuration.getInstance();
    private Connection conn;

    public TableBuilder(Connection conn) {
        this.conn = conn;
    }

    Table build(String tableName, Class<? extends Model> model, String sql) throws SQLException {
        Table table = new Table(tableName, model);
        Map<String, Class<?>> columnAndTypes = new HashMap<String, Class<?>>();
        table.setColumnAndTypes(columnAndTypes);

        //设置主键
        primarkKeysBuilder(tableName, table);

        //设置字段
        columnsBuilder(sql, columnAndTypes);

        if (instance.isDevMode()) {
            Reporter reporter = instance.getReporter();
            reporter.report(table.toString());
        }

        return table;
    }

    private void columnsBuilder(String sql, Map<String, Class<?>> columnAndTypes) throws SQLException {
        ResultSet rs = query(conn, sql);
        ResultSetMetaData rsmd = rs.getMetaData();
        int columnCount = rsmd.getColumnCount();

        for (int index = 1; index <= columnCount; index++) {
            String columnName = rsmd.getColumnName(index);
            String columnType = rsmd.getColumnClassName(index);
            Class<?> type = ColumnTypeHelper.convert(columnType);
            if (type == null) {
                throw new IllegalArgumentException("The column type [" + columnType + "] undefined Class type");
            }
            columnAndTypes.put(columnName, type);
        }

        DbUtils.close(rs);
    }

    private ResultSet query(Connection conn, String sql) {
        try {
            PreparedStatement ps = conn.prepareStatement(sql);
            return ps.executeQuery();
        } catch (SQLException e) {
            throw new SqlExecuteException(e);
        }
    }

    private void primarkKeysBuilder(String tableName, Table table) throws SQLException {
        DatabaseMetaData dbmd = conn.getMetaData();
        ResultSet pkrs = dbmd.getPrimaryKeys(null, null, tableName);
        String[] pks = parsePrimaryKeys(pkrs);
        table.setPrimaryKeys(pks);

        DbUtils.close(pkrs);
    }

    private String[] parsePrimaryKeys(ResultSet rs) throws SQLException {
        List<String> list = new ArrayList<String>();
        while (rs.next()) {
            String columnName = rs.getString("COLUMN_NAME");
            list.add(columnName);
        }
        int size = list.size();
        String[] pks = new String[size];
        for (int index = 0; index < size; index++) {
            pks[index] = list.get(index);
        }
        return pks;

    }

}
